/* CsJni - .NET / Java Bridge
 * 
 * Copyright 2010 Robert E. Burke Licensed under the Apache License, Version 
 * 2.0 (the "License"); you may not use this file except in compliance with 
 * the License. You may obtain a copy of the License at 
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable 
 * law or agreed to in writing, software distributed under the License is 
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
 * KIND, either express or implied. See the License for the specific language 
 * governing permissions and limitations under the License. 
*/

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics.CodeAnalysis;

namespace CsJni
{
    public sealed class JniField : JniMember
    {
        internal JniField(IntPtr handle, JniClass declaringClass, bool isStatic, string signature)
            : base(handle, declaringClass, isStatic, signature)
        {
        }

        public JniObject GetObjectField(
            JniEnvironment environment,
            JniObject jniObject)
        {
            VerifyObjectReturnType();
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            IntPtr result = JniEnvironment.Functions.GetObjectField(environment.Handle, jniObject.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return JniObject.CreateReturnObject(environment, result, this);
        }

        public string GetStringField(
            JniEnvironment environment,
            JniObject jniObject)
        {
            VerifyReturnType(JniType.String);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            IntPtr result = JniEnvironment.Functions.GetObjectField(environment.Handle, jniObject.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return JniString.ExtractAndRelease(environment, result);
        }

        public bool GetBooleanField(
            JniEnvironment environment,
            JniObject jniObject)
        {
            VerifyReturnType(JniType.Boolean);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            byte result = JniEnvironment.Functions.GetBooleanField(environment.Handle, jniObject.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return JBooleanConverter.From(result);
        }

        public byte GetByteField(
            JniEnvironment environment,
            JniObject jniObject)
        {
            VerifyReturnType(JniType.Byte);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            byte result = JniEnvironment.Functions.GetByteField(environment.Handle, jniObject.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        public char GetCharField(
            JniEnvironment environment,
            JniObject jniObject)
        {
            VerifyReturnType(JniType.Char);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            char result = JniEnvironment.Functions.GetCharField(environment.Handle, jniObject.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        // OK to suppress, match JNI name & signature
        [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "short")]
        public short GetShortField(
            JniEnvironment environment,
            JniObject jniObject)
        {
            VerifyReturnType(JniType.Short);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            short result = JniEnvironment.Functions.GetShortField(environment.Handle, jniObject.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        // OK to suppress, match JNI name & signature
        [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "int")]
        public int GetIntField(
            JniEnvironment environment,
            JniObject jniObject)
        {
            VerifyReturnType(JniType.Int);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            int result = JniEnvironment.Functions.GetIntField(environment.Handle, jniObject.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        // OK to suppress, match JNI name & signature
        [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "long")]
        public long GetLongField(
            JniEnvironment environment,
            JniObject jniObject)
        {
            VerifyReturnType(JniType.Long);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            long result = JniEnvironment.Functions.GetLongField(environment.Handle, jniObject.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        // OK to suppress, match JNI name & signature
        [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "float")]
        public float GetFloatField(
            JniEnvironment environment,
            JniObject jniObject)
        {
            VerifyReturnType(JniType.Float);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            float result = JniEnvironment.Functions.GetFloatField(environment.Handle, jniObject.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        public double GetDoubleField(
            JniEnvironment environment,
            JniObject jniObject)
        {
            VerifyReturnType(JniType.Double);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            double result = JniEnvironment.Functions.GetDoubleField(environment.Handle, jniObject.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        public void SetObjectField(
            JniEnvironment environment,
            JniObject jniObject,
            JniObject value
            )
        {
            VerifyObjectReturnType();
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            // NOTE: OK if "JniObject value" is null
            IntPtr safeValue = ((value == null) ? IntPtr.Zero : value.Handle);
            JniEnvironment.Functions.SetObjectField(environment.Handle, jniObject.Handle, this.Handle, safeValue);
            JniThrowable.CheckException(environment);
        }

        public void SetStringField(
            JniEnvironment environment,
            JniObject jniObject,
            string value
            )
        {
            VerifyReturnType(JniType.String);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            // NOTE: OK if "string value" is null
            IntPtr safeValue = ((value == null) ? IntPtr.Zero : JniString.NewStringCore(environment, value));
            try
            {
                JniEnvironment.Functions.SetObjectField(environment.Handle, jniObject.Handle, this.Handle, safeValue);
                JniThrowable.CheckException(environment);
            }
            finally
            {
                if (safeValue != IntPtr.Zero)
                {
                    JniEnvironment.Functions.DeleteLocalRef(environment.Handle, safeValue);
                    // EXCEPTION CHECK: Do nothing, this method safe to call while exception is pending, does
                    // not raise additional exceptions.
                }
            }
        }

        public void SetBooleanField(
            JniEnvironment environment,
            JniObject jniObject,
            bool value
            )
        {
            VerifyReturnType(JniType.Boolean);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            JniEnvironment.Functions.SetBooleanField(environment.Handle, jniObject.Handle, this.Handle, JBooleanConverter.To(value));
            JniThrowable.CheckException(environment);
        }

        public void SetByteField(
            JniEnvironment environment,
            JniObject jniObject,
            byte value
            )
        {
            VerifyReturnType(JniType.Byte);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            JniEnvironment.Functions.SetByteField(environment.Handle, jniObject.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetCharField(
            JniEnvironment environment,
            JniObject jniObject,
            char value
            )
        {
            VerifyReturnType(JniType.Char);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            JniEnvironment.Functions.SetCharField(environment.Handle, jniObject.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetShortField(
            JniEnvironment environment,
            JniObject jniObject,
            short value
            )
        {
            VerifyReturnType(JniType.Short);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            JniEnvironment.Functions.SetShortField(environment.Handle, jniObject.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetIntField(
            JniEnvironment environment,
            JniObject jniObject,
            int value
            )
        {
            VerifyReturnType(JniType.Int);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            JniEnvironment.Functions.SetIntField(environment.Handle, jniObject.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetLongField(
            JniEnvironment environment,
            JniObject jniObject,
            long value
            )
        {
            VerifyReturnType(JniType.Long);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            JniEnvironment.Functions.SetLongField(environment.Handle, jniObject.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetFloatField(
            JniEnvironment environment,
            JniObject jniObject,
            float value
            )
        {
            VerifyReturnType(JniType.Float);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            JniEnvironment.Functions.SetFloatField(environment.Handle, jniObject.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetDoubleField(
            JniEnvironment environment,
            JniObject jniObject,
            double value
            )
        {
            VerifyReturnType(JniType.Double);
            VerifyEnvironment(environment);
            VerifyNotStatic();
            VerifyInputJniObject(jniObject);
            JniEnvironment.Functions.SetDoubleField(environment.Handle, jniObject.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public JniObject GetStaticObjectField(
            JniEnvironment environment)
        {
            VerifyObjectReturnType();
            VerifyEnvironment(environment);
            VerifyStatic();
            IntPtr result = JniEnvironment.Functions.GetStaticObjectField(environment.Handle, this.DeclaringClass.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return JniObject.CreateReturnObject(environment, result, this);
        }

        public string GetStaticStringField(
            JniEnvironment environment)
        {
            VerifyReturnType(JniType.String);
            VerifyEnvironment(environment);
            VerifyStatic();
            IntPtr result = JniEnvironment.Functions.GetStaticObjectField(environment.Handle, this.DeclaringClass.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return JniString.ExtractAndRelease(environment, result);
        }

        public bool GetStaticBooleanField(
            JniEnvironment environment)
        {
            VerifyReturnType(JniType.Boolean);
            VerifyEnvironment(environment);
            VerifyStatic();
            byte result = JniEnvironment.Functions.GetStaticBooleanField(environment.Handle, this.DeclaringClass.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return JBooleanConverter.From(result);
        }

        public byte GetStaticByteField(
            JniEnvironment environment)
        {
            VerifyReturnType(JniType.Byte);
            VerifyEnvironment(environment);
            VerifyStatic();
            byte result = JniEnvironment.Functions.GetStaticByteField(environment.Handle, this.DeclaringClass.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        public char GetStaticCharField(
            JniEnvironment environment)
        {
            VerifyReturnType(JniType.Char);
            VerifyEnvironment(environment);
            VerifyStatic();
            char result = JniEnvironment.Functions.GetStaticCharField(environment.Handle, this.DeclaringClass.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        // OK to suppress, match JNI name & signature
        [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "short")]
        public short GetStaticShortField(
            JniEnvironment environment)
        {
            VerifyReturnType(JniType.Short);
            VerifyEnvironment(environment);
            VerifyStatic();
            short result = JniEnvironment.Functions.GetStaticShortField(environment.Handle, this.DeclaringClass.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        // OK to suppress, match JNI name & signature
        [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "int")]
        public int GetStaticIntField(
            JniEnvironment environment)
        {
            VerifyReturnType(JniType.Int);
            VerifyEnvironment(environment);
            VerifyStatic();
            int result = JniEnvironment.Functions.GetStaticIntField(environment.Handle, this.DeclaringClass.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        // OK to suppress, match JNI name & signature
        [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "long")]
        public long GetStaticLongField(
            JniEnvironment environment)
        {
            VerifyReturnType(JniType.Long);
            VerifyEnvironment(environment);
            VerifyStatic();
            long result = JniEnvironment.Functions.GetStaticLongField(environment.Handle, this.DeclaringClass.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        // OK to suppress, match JNI name & signature
        [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "float")]
        public float GetStaticFloatField(
            JniEnvironment environment)
        {
            VerifyReturnType(JniType.Float);
            VerifyEnvironment(environment);
            VerifyStatic();
            float result = JniEnvironment.Functions.GetStaticFloatField(environment.Handle, this.DeclaringClass.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        public double GetStaticDoubleField(
            JniEnvironment environment)
        {
            VerifyReturnType(JniType.Double);
            VerifyEnvironment(environment);
            VerifyStatic();
            double result = JniEnvironment.Functions.GetStaticDoubleField(environment.Handle, this.DeclaringClass.Handle, this.Handle);
            JniThrowable.CheckException(environment);
            return result;
        }

        public void SetStaticObjectField(
            JniEnvironment environment,
            JniObject value
            )
        {
            VerifyObjectReturnType();
            VerifyEnvironment(environment);
            VerifyStatic();
            // NOTE: OK if "JniObject value" is null
            IntPtr safeValue = ((value == null) ? IntPtr.Zero : value.Handle);
            JniEnvironment.Functions.SetStaticObjectField(environment.Handle, this.DeclaringClass.Handle, this.Handle, safeValue);
            JniThrowable.CheckException(environment);
        }

        public void SetStaticStringField(
            JniEnvironment environment,
            string value
            )
        {
            VerifyReturnType(JniType.String);
            VerifyEnvironment(environment);
            VerifyStatic();
            // NOTE: OK if "string value" is null
            IntPtr safeValue = ((value == null) ? IntPtr.Zero : JniString.NewStringCore(environment, value));
            try
            {
                JniEnvironment.Functions.SetStaticObjectField(environment.Handle, this.DeclaringClass.Handle, this.Handle, safeValue);
                JniThrowable.CheckException(environment);
            }
            finally
            {
                if (safeValue != IntPtr.Zero)
                {
                    JniEnvironment.Functions.DeleteLocalRef(environment.Handle, safeValue);
                    // EXCEPTION CHECK: Do nothing, this method safe to call while exception is pending, does
                    // not raise additional exceptions.
                }
            }
        }

        public void SetStaticBooleanField(
            JniEnvironment environment,
            bool value
            )
        {
            VerifyReturnType(JniType.Boolean);
            VerifyEnvironment(environment);
            VerifyStatic();
            JniEnvironment.Functions.SetStaticBooleanField(environment.Handle, this.DeclaringClass.Handle, this.Handle, JBooleanConverter.To(value));
            JniThrowable.CheckException(environment);
        }

        public void SetStaticByteField(
            JniEnvironment environment,
            byte value
            )
        {
            VerifyReturnType(JniType.Byte);
            VerifyEnvironment(environment);
            VerifyStatic();
            JniEnvironment.Functions.SetStaticByteField(environment.Handle, this.DeclaringClass.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetStaticCharField(
            JniEnvironment environment,
            char value
            )
        {
            VerifyReturnType(JniType.Char);
            VerifyEnvironment(environment);
            VerifyStatic();
            JniEnvironment.Functions.SetStaticCharField(environment.Handle, this.DeclaringClass.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetStaticShortField(
            JniEnvironment environment,
            short value
            )
        {
            VerifyReturnType(JniType.Short);
            VerifyEnvironment(environment);
            VerifyStatic();
            JniEnvironment.Functions.SetStaticShortField(environment.Handle, this.DeclaringClass.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetStaticIntField(
            JniEnvironment environment,
            int value
            )
        {
            VerifyReturnType(JniType.Int);
            VerifyEnvironment(environment);
            VerifyStatic();
            JniEnvironment.Functions.SetStaticIntField(environment.Handle, this.DeclaringClass.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetStaticLongField(
            JniEnvironment environment,
            long value
            )
        {
            VerifyReturnType(JniType.Long);
            VerifyEnvironment(environment);
            VerifyStatic();
            JniEnvironment.Functions.SetStaticLongField(environment.Handle, this.DeclaringClass.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetStaticFloatField(
            JniEnvironment environment,
            float value
            )
        {
            VerifyReturnType(JniType.Float);
            VerifyEnvironment(environment);
            VerifyStatic();
            JniEnvironment.Functions.SetStaticFloatField(environment.Handle, this.DeclaringClass.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }

        public void SetStaticDoubleField(
            JniEnvironment environment,
            double value
            )
        {
            VerifyReturnType(JniType.Double);
            VerifyEnvironment(environment);
            VerifyStatic();
            JniEnvironment.Functions.SetStaticDoubleField(environment.Handle, this.DeclaringClass.Handle, this.Handle, value);
            JniThrowable.CheckException(environment);
        }
    }
}
